# -*- coding: utf-8 -*-
# Author   : ZhangQing
# Time     : 2025-07-15 23:12
# File     : finnhub_adapter.py
# Project  : dynamic-portfolio-optimizer
# Desc     :
# src/data/adapters/finnhub_adapter.py
import finnhub
from typing import Dict, List, Any
import pandas as pd
from datetime import datetime
from .base_adapter import BaseDataAdapter, RateLimitDecorator


class FinnhubAdapter(BaseDataAdapter):
    """Finnhub数据适配器"""

    def __init__(self, config):
        super().__init__(config)
        self.client = finnhub.Client(api_key=config.api_key)

    @RateLimitDecorator(calls=60, period=60)
    def get_stock_data(self, symbol: str, start_date: datetime,
                       end_date: datetime, interval: str = '1d') -> pd.DataFrame:
        """获取股票数据"""
        try:
            # 转换时间间隔
            resolution_map = {
                '1m': '1',
                '5m': '5',
                '15m': '15',
                '30m': '30',
                '1h': '60',
                '1d': 'D'
            }

            resolution = resolution_map.get(interval, 'D')

            # 获取数据
            candles = self.client.stock_candles(
                symbol=symbol,
                resolution=resolution,
                _from=int(start_date.timestamp()),
                to=int(end_date.timestamp())
            )

            if candles['s'] != 'ok':
                self.logger.warning(f"Finnhub: 未获取到{symbol}的数据")
                return pd.DataFrame()

                # 转换为DataFrame
                data = pd.DataFrame({
                    'timestamp': pd.to_datetime(candles['t'], unit='s'),
                    'open': candles['o'],
                    'high': candles['h'],
                    'low': candles['l'],
                    'close': candles['c'],
                    'volume': candles['v']
                })

                data.set_index('timestamp', inplace=True)
                data['source'] = 'finnhub'
                data['symbol'] = symbol

                return self.standardize_data(data)

        except Exception as e:
            self.logger.error(f"Finnhub获取股票数据失败: {e}")
            return pd.DataFrame()

    def get_options_data(self, symbol: str, expiration_date: datetime) -> pd.DataFrame:
        """获取期权数据 (Finnhub不支持期权数据)"""
        self.logger.info("Finnhub不支持期权数据")
        return pd.DataFrame()

    @RateLimitDecorator(calls=60, period=60)
    def get_fundamentals(self, symbol: str) -> Dict[str, Any]:
        """获取基本面数据"""
        try:
            # 获取公司概况
            profile = self.client.company_profile2(symbol=symbol)

            if not profile:
                self.logger.warning(f"Finnhub: 未获取到{symbol}的基本面数据")
                return {}

            # 获取基本财务数据
            try:
                basic_financials = self.client.company_basic_financials(symbol, 'all')
                metrics = basic_financials.get('metric', {})
            except:
                metrics = {}

            fundamentals = {
                'symbol': symbol,
                'company_name': profile.get('name', ''),
                'sector': profile.get('finnhubIndustry', ''),
                'industry': profile.get('ggroup', ''),
                'market_cap': profile.get('marketCapitalization', 0),
                'pe_ratio': metrics.get('peBasicExclExtraTTM', 0),
                'pb_ratio': metrics.get('pbAnnual', 0),
                'dividend_yield': metrics.get('dividendYieldIndicatedAnnual', 0),
                'beta': metrics.get('beta', 0),
                'eps': metrics.get('epsBasicExclExtraItemsTTM', 0),
                'revenue': metrics.get('totalRevenueTTM', 0),
                'gross_margin': metrics.get('grossMarginTTM', 0),
                'profit_margin': metrics.get('netProfitMarginTTM', 0),
                'roe': metrics.get('roeTTM', 0),
                'roa': metrics.get('roaTTM', 0),
                'source': 'finnhub'
            }

            return fundamentals

        except Exception as e:
            self.logger.error(f"Finnhub获取基本面数据失败: {e}")
            return {}

    @RateLimitDecorator(calls=60, period=60)
    def get_news(self, symbol: str, limit: int = 10) -> List[Dict[str, Any]]:
        """获取新闻数据"""
        try:
            # 获取公司新闻
            news_items = self.client.company_news(
                symbol=symbol,
                _from=datetime.now().strftime('%Y-%m-%d'),
                to=datetime.now().strftime('%Y-%m-%d')
            )

            processed_news = []
            for item in news_items[:limit]:
                processed_news.append({
                    'symbol': symbol,
                    'title': item.get('headline', ''),
                    'summary': item.get('summary', ''),
                    'url': item.get('url', ''),
                    'published_at': datetime.fromtimestamp(item.get('datetime', 0)),
                    'source': 'finnhub',
                    'category': item.get('category', ''),
                    'related_symbols': item.get('related', [])
                })

            return processed_news

        except Exception as e:
            self.logger.error(f"Finnhub获取新闻数据失败: {e}")
            return []
